﻿#include "SceneNode.h"
#include "..\GameEngine.h"
#include "..\Exceptions\RootEntityException.h"
#include "..\Games\MyGame.h"

SceneNode::SceneNode(SceneNode * nameOfParentSceneNode) : _parentSceneNode(nameOfParentSceneNode){
	this->_destroy = false;
}

SceneNode::~SceneNode() {
}

void SceneNode::addEntity(GameEntity * entity) {
	if(_parentSceneNode == NULL && entity->getName() != "camera") 			//If the current node is the root and it is not the camera then it is impossible to add the entity
		throw RootEntityException("You cannot add an entity to the root!");	//If it is the root node and not the camera: throw exception, this is illegal!
	else {	
		entity->setMySceneNode(this);										//set the SceneNode of the Added Entity
		entities.push_back(entity);											//add the entity to the list
	}
}

void SceneNode::removeEntity(GameEntity * entity) {
	entities.remove(entity);												//Remove the entity from the list
}		

GameEntity * SceneNode::getEntity(const std::string& s) {
	std::list<GameEntity *>::iterator it;									//First search the entities
	for(it=entities.begin(); it != entities.end(); ++it)
		if((*it)->getName().compare(s) == 0)
			return (*it);
	
	std::list<SceneNode *>::iterator it2;									//...and then search the children
	for(it2=children.begin() ; it2 != children.end(); ++it2) 
		if((*it2)->getEntity(s) != NULL)
			return (*it2)->getEntity(s);
	
	return NULL;															//If no entity is found return NULL
}	

void SceneNode::removeAllEntities() {
	while(!entities.empty()) {
		entities.erase(entities.end());										//Remove each entity
	}
}

void SceneNode::deleteAllEntities() {
	entities.clear();														//All the elements in the list container are dropped: their destructors are called, 
}																			//and then they are removed from the list container, leaving it with a size of 0.

std::list<SceneNode *> SceneNode::getChildren() {
	return children;
}

std::list<GameEntity *> SceneNode::getEntities() {
	return entities;
}

SceneNode * SceneNode::createChildSceneNode() {
	SceneNode * r = new SceneNode(this);									//This object is the parent of its child
	children.push_back(r);													//add it to the child list of the Scene Node
	return r;
}

void SceneNode::removeChildSceneNode(SceneNode * s) {
	//children.remove(s);
	std::list<SceneNode *>::iterator it;
	for(it=children.begin(); it != children.end(); ++it) {
		if((*it) == s) {
			children.size();
			children.remove((*it));
			children.size();
			break;
		}
	}
}
SceneNode * SceneNode::getParentSceneNode() const {
	return _parentSceneNode;
}

void SceneNode::deleteAllChildrenSceneNodes() {
	children.clear();
}

void SceneNode::deleteAllChilderAndEntitiesSceneNode() {
	children.clear();
	entities.clear();
	MyGame::Instance()->cleanContainer();
}

ORIENTATION SceneNode::getOrientation() const {
	return orientation;
}

void SceneNode::setOrientation(ORIENTATION v) {
	orientation = v;
}

POINT3D SceneNode::getPosition() const {
	return position;
}

void SceneNode::setPosition(POINT3D v) {
	this->position = v;

	std::list<SceneNode *>::iterator it;									//Set the position of the children as well
	for(it=children.begin() ; it != children.end(); ++it) 
		(*it)->setPosition(v);
}

void SceneNode::updateSceneNode() {
	this->checkNodesAlive();
	std::list<GameEntity *>::iterator it1, it2; //First update all the entities...

	for(it1=entities.begin() ; it1 != entities.end(); ++it1)
	{
		(*it1)->update();
	}
	std::list<SceneNode *>::iterator it3, it4;									//...and then the children
	for(it3=children.begin() ; it3 != children.end(); ++it3) {
		enterRenderingSceneNode();
		(*it3)->updateSceneNode();
		exitRenderingSceneNode();
	}
								
}

void SceneNode::checkNodesAlive() {
	bool toDestroy = false;
	std::list<SceneNode *>::iterator it3;	
	for(it3=children.begin() ; it3 != children.end(); ++it3) {
		if((*it3)->toDestroy() == true) {
			MyGame::Instance()->deleteFromContainer((*it3)->getEntities());
			(*it3)->deleteAllEntities();
			(*it3)->deleteAllChildrenSceneNodes();
			children.remove(*it3);
			break;
		}
	}			
}

void SceneNode::renderSceneNode() {
	//enterRenderingSceneNode();
	std::list<GameEntity *>::iterator it1;									//First draw all the entities
	for(it1=entities.begin() ; it1 != entities.end(); ++it1) {
		enterRenderingSceneNode();
		(*it1)->draw();
		exitRenderingSceneNode();
	}
	
	
	std::list<SceneNode *>::iterator it;									//..and then the children
	for(it=children.begin() ; it != children.end(); ++it) 
	{
		(*it)->renderSceneNode();
	}
	//exitRenderingSceneNode();
	
}

void SceneNode::enterRenderingSceneNode() {
	GameEngine::Instance()->getRenderer()->enterContext();
}

void SceneNode::exitRenderingSceneNode() {
	GameEngine::Instance()->getRenderer()->exitContext();
}

bool SceneNode::write(std::ostream& os) const {
	os << "*NROFENTITIES*";
	os << entities.size();

	std::list<GameEntity *>::const_iterator it1;								//First search the entities
	for(it1 =entities.begin(); it1 != entities.end(); ++it1) {
		(*it1)->write(os);
		os << "*TYPE*";
		os << (*it1)->getType();
		//os << *it1;
	}
	
	os << "*OR*";
	os << this->orientation.degree;
	os << ",";
	os << this->orientation.orientVect.x;
	os << ",";
	os << this->orientation.orientVect.y;
	os << ",";
	os << this->orientation.orientVect.z;
	os << "*POS*";
	os << this->position.x;
	os << ",";
	os << this->position.y;
	os << ",";
	os << this->position.z;
	
	os << "*NROFCHILDREN*";
	os << children.size();
	os << "*NODEEOF*\n";

	std::list<SceneNode *>::const_iterator it;
	for(it = children.begin() ; it != children.end(); ++it) {
		(*it)->write(os);
	}
	//os << "*";
	
	//toString needed for this ones -> Levent
	//os << this->orientation.degree;
	//os << this->position.x;
	//os << this->position.y;
	//os << this->position.z;
	//os << "*NODEEOF*";
	//lol
	//Save the children nodes
	//save the pointer to entities
	//save the entities
	//save orientation and position
	return false;
}

void SceneNode::read(std::istream& i) {
	//std::ofstream outfile("blabla.txt");
	std::list<std::string> nodelist;
	std::string node1;
	std::string node2;
	bool isCamera = false;
	int maxFreq = -1;
	int nrOfChilds = -1;
	int nrOfEntities;
	int type;
	std::string name;
	ORIENTATION orientation;
	POINT3D position;
	COLOR color;
	int parserstate = 0;
	char *pch;
	i >> node1;
	while(node1 != "*EOF*") {
		//nodelist.push_back(node1);
		//node1.find("*ENTITYCAMERA*");
		char *node2 = new char[node1.size()];
		strcpy(node2,node1.c_str());
		pch = strtok (node2," *");
		while (pch != NULL)
		{
			//outfile << pch;
			if(strcmp(pch,"ENTITYCAMERA") == 0) {
				isCamera = true;
			}
			if(strcmp(pch,"NROFENTITIES") == 0) {
				pch = strtok (NULL, " ,*");
				nrOfEntities = atoi(pch);
				parserstate++;
			}
			if(strcmp(pch,"ENTITY") == 0) {
				pch = strtok (NULL, " ,*");
				color.r = atof(pch);
				pch = strtok (NULL, " ,*");
				color.g = atof(pch);
				pch = strtok (NULL, " ,*");
				color.b = atof(pch);
				parserstate++;
			}
			if(strcmp(pch,"TYPE") == 0) {
				pch = strtok (NULL, " ,*");
				type = atoi(pch);
				parserstate++;
			}
			if(strcmp(pch,"NAME") == 0) {
				pch = strtok (NULL, " ,*");
				name = pch;
				parserstate++;
			}
			if(strcmp(pch,"FREQ") == 0) {
				pch = strtok (NULL, " ,*");
				maxFreq = atoi(pch);
				parserstate++;
			}
			if(strcmp(pch,"NROFCHILDREN") == 0) {
				pch = strtok (NULL, " ,*");
				nrOfChilds = atoi(pch);
				parserstate++;
			}
			if(strcmp(pch,"OR") == 0) {
				pch = strtok (NULL, " ,*");
				orientation.degree = atof(pch);
				pch = strtok (NULL, " ,*");
				orientation.orientVect.x = atof(pch);
				pch = strtok (NULL, " ,*");
				orientation.orientVect.y =atof(pch);
				pch = strtok (NULL, " ,*");
				orientation.orientVect.z = atof(pch);
				parserstate++;
			}
			if(strcmp(pch,"POS") == 0) {
				pch = strtok (NULL, " ,*");
				position.x = atof(pch);
				pch = strtok (NULL, " ,*");
				position.y = atof(pch);
				pch = strtok (NULL, " ,*");
				position.z = atof(pch);
				parserstate++;
			}
			pch = strtok (NULL, " ,*");
			if(isCamera == true) {
				if(maxFreq != -1 && nrOfChilds != -1) {
					MyGame::Instance()->createCamera(maxFreq,nrOfChilds);
					i >> node1;
					char *node2 = new char[node1.size()];
					strcpy(node2,node1.c_str());
					pch = strtok (node2," *");
					isCamera = false;
					parserstate = 0;
				}
			}
			else if(parserstate == 8) {
				MyGame::Instance()->createEntity(NULL, nrOfChilds,type,maxFreq,name,orientation,position,color);
				parserstate = 0;		
			}
		}
		i >> node1;
	}
	//outfile << nodelist.size()
	//outfile.close();
	//replace current scenegraph with the new one*/
}


int SceneNode::getChildsToCreate() {
	return _childsToCreate;
}

void SceneNode::setChildsToCreate(int childsToCreate) {
	_childsToCreate = childsToCreate;
}

void SceneNode::destroy() {
	_destroy = true;
}

bool SceneNode::toDestroy() {
	return _destroy;
}